#include"socket.hpp"

#include<fcntl.h>

#include<sys/select.h>

class selectserver
{
public:
    selectserver()
    {
        FD_ZERO(&_fs);
    }
    void init()
    {
        _sk.my_socket();
        _sk.my_bind("0.0.0.0", 8080);
        _sk.my_listen();
        FD_SET(_sk.get_sockfd(), &_fs);
        _max_fd = _sk.get_sockfd();
    }

    void event_hander(const fd_set& fs)
    {
        char buffer[1024] = {0};
        for(int i = 0; i <= _max_fd; ++i)
        {
            if(FD_ISSET(i, &fs))
            {
                if(i == _sk.get_sockfd())
                {
                    std::cout << "get a new accept" << std::endl;
                    std::string clientip;
                    int16_t port = 0;
                    int acc_fd = _sk.my_accept(clientip, port); // accept时，时间已经就绪，不用等待啦
                    if(acc_fd >= sizeof(fd_set) * 8) 
                    {
                        std::cout << "out of the range of select, can not accept" << std::endl;
                        close(acc_fd);
                    }
                    else
                    {
                        FD_SET(acc_fd, &_fs);
                        _max_fd = std::max(_max_fd, acc_fd);
                    } 
                }
                else
                {
                    ssize_t n = read(i, buffer, sizeof(buffer)); // 读的时候，时间已经就绪，不用等待啦
                    if(n < 0)
                    {
                        perror("read");
                        return;
                    }
                    else if(n == 0)
                    {
                        std::cout << "fd " << i << " is closed, close it and back." << std::endl;
                        close(i);
                        FD_CLR(i, &_fs);
                        return;
                    }
                    else
                    {
                        buffer[n] = 0;
                        std::cout << buffer;
                        write(i, buffer, n);
                    }
                }
            }
        }
    }

    void start()
    {
        while(1)
        {
            // fd_set cy_fs = _fs; // 可以但不推荐，可能有些平台出错
            fd_set cy_fs; // 因为是输入输出型参数，所以不能反复使用，每一个循环创建一个
            FD_ZERO(&cy_fs);
            for(int i = 0; i < sizeof(fd_set) * 8; ++i)
                if(FD_ISSET(i, &_fs))
                    FD_SET(i, &cy_fs);
            
            timeval otime; // 因为是输入输出型参数，所以不能反复使用，每一个循环创建一个
            otime.tv_sec = 0;
            otime.tv_usec = 5;
            int n = select(_max_fd + 1, &cy_fs, nullptr, nullptr, nullptr);
            if(n < 0)
            {
                perror("select");
                return;
            }
            else if(n == 0)
            {
                std::cout << "time out" << std::endl;
            }
            else
            {
                event_hander(cy_fs);
            }
        }
    }
private:
    sock _sk;
    fd_set _fs;
    int _max_fd;
};